]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st/theme-context: Run dispose on theme nodes on theme context changes
authorJonas Dreßler <verdre@v0yd.nl>
Thu, 24 Jul 2025 16:27:29 +0000 (18:27 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Sat, 13 Sep 2025 17:03:01 +0000 (19:03 +0200)
When the theme context changes, we clear the theme cache and make the
widget tree throw away and create new theme nodes. That's because the
old theme nodes can no longer be used, they might be referencing old
CSS data, scale factors, or other things.

St itself should never reuse theme nodes after theme context changes,
but of course theme nodes are exposed to users of St, and they can
always keep a theme node around and call a method on it even after a
theme context change.

To avoid those outdated theme nodes accessing outdated pointers into
the Croco structures and causing crashes, force-run their `dispose()`
function when the theme context changes. This should ensure that all
problematic pointers in the theme nodes are cleared, and users of St
can't crash gnome-shell.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3809>
(cherry picked from commit 41758311d1df0f40ae969b8d57cf3302ad2a5803)

src/st/st-theme-context.c

index eb24212e1286e2887bc4defe4d04be612bae9902..5b066d2696162a42ebd0562e811aaf9737daaa40 100644 (file)
@@ -311,11 +311,24 @@ static void
 st_theme_context_changed (StThemeContext *context)
 {
   StThemeNode *old_root = context->root_node;
+  g_autoptr (GPtrArray) old_nodes = NULL;
+
   context->root_node = NULL;
-  g_hash_table_remove_all (context->nodes);
+  old_nodes = g_hash_table_steal_all_keys (context->nodes);
 
   g_signal_emit (context, signals[CHANGED], 0);
 
+  /* Force a run of the dispose() vfuncs of theme nodes so that their references
+   * into the theme CSS data get cleared. While theme nodes might outlive this
+   * function (in case buggy user code is holding a reference to them), the theme
+   * CSS data definitely gets freed after this function returns.
+   *
+   * Note that we can't do this before emitting ::changed because during the
+   * signal emission, StWidget needs to access the theme nodes (and therefore the
+   * theme CSS data) for its old/new theme node comparisons.
+   */
+  g_ptr_array_foreach (old_nodes, (GFunc) g_object_run_dispose, NULL);
+
   if (old_root)
     g_object_unref (old_root);
 }
@@ -599,4 +612,4 @@ st_theme_context_get_resolution (StThemeContext *context)
   g_return_val_if_fail (ST_IS_THEME_CONTEXT (context), -1);
 
   return clutter_backend_get_resolution (context->clutter_backend);
-}
\ No newline at end of file
+}